import $ from 'jquery'
import './index.scss'
import lrcData from './lrc.json'
import configData from './config.json'
import './resource/HowLongWillILoveYou.mp3'

var particleImg = require(`./resource/${configData.imgSrc}`) // eslint-disable-line
var ParticleCanvas = document.getElementById('myParticle')
ParticleCanvas.setAttribute('width', window.innerWidth)
ParticleCanvas.setAttribute('height', window.innerHeight)
ShowLrcWithAudio.lrcData = lrcData

function ParticleAnimation(canvas) {
	this.canvas = canvas
	this.ctx = canvas.getContext('2d')
	this.particles = []
	this.requestID = 0
}

ParticleAnimation.prototype.beginAnimation = function() {
	// eslint-disable-next-line no-undef
	var img = new Image()
	this.img = img
	img.src = particleImg
	img.onload = () => {
		this.ctx.drawImage(img, 0, 0)
		var imageData = this.ctx.getImageData(0, 0, img.width, img.height)
		this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
		this.calculateParticles(img, imageData)
		this.draw.objContext = this
		this.drawStars()
		printWords()
	}
}
ParticleAnimation.prototype.drawStars = function() {
	this.ctx.clearRect(
		this.canvas.width / 2 - (this.img.width * 4) / 3,
		0,
		this.img.width,
		this.img.height
	)
	var currentParticle = null
	for (var i = 0; i < this.particles.length; i++) {
		currentParticle = this.particles[i]
		this.ctx.fillStyle = currentParticle.fillStyle
	}
}
ParticleAnimation.prototype.draw = function() {
	var objContext = ParticleAnimation.prototype.draw.objContext
	var len = objContext.particles.length
	var curParticle = null
	var curX = 0
	var curY = 0
	if (
		objContext.particles[len - 1].durationNum <
		objContext.particles[len - 1].currentTimeNum
	) {
		window.cancelAnimationFrame(objContext.requestID)
		return
	} else
		objContext.ctx.clearRect(
			0,
			0,
			objContext.canvas.width,
			objContext.canvas.height
		)
	for (var i = 0; i < len; i++) {
		curParticle = objContext.particles[i]
		if (curParticle.delayCountDownNum++ > curParticle.delayNum) {
			objContext.ctx.fillStyle =
				curParticle.durationNum - curParticle.currentTimeNum > 300
					? `rgba(255,255,255,${Math.random() * 0.6 + 0.4})`
					: curParticle.fillStyle
			if (curParticle.currentTimeNum < curParticle.durationNum) {
				curX = objContext.easeInOutExpo(
					curParticle.currentTimeNum,
					curParticle.startX,
					curParticle.x - curParticle.startX,
					curParticle.durationNum
				)
				curY = objContext.easeInOutExpo(
					curParticle.currentTimeNum,
					curParticle.startY,
					curParticle.y - curParticle.startY,
					curParticle.durationNum
				)
				objContext.ctx.fillRect(curX, curY, 1, 1)
				curParticle.currentTimeNum++
			} else {
				objContext.ctx.fillRect(curParticle.x, curParticle.y, 1, 1)
				curParticle.currentTimeNum++
			}
		}
	}
	objContext.requestID = window.requestAnimationFrame(objContext.draw)
}
ParticleAnimation.prototype.calculateParticles = function(img, imgData) {
	var cols = 100
	var rows = 100
	var canvasWidth = this.canvas.width
	var imgWidth2X = this.img.width * 2
	var imgX =
		canvasWidth <= imgWidth2X
			? (imgWidth2X - canvasWidth) / 2
			: (canvasWidth - imgWidth2X) / 4
	var sWidth = parseInt(img.width / cols)
	var sHeight = parseInt(img.height / rows)
	var data = imgData.data
	var pos = 0
	for (var j = 1; j <= cols; j++) {
		for (var i = 1; i <= rows; i++) {
			pos = [(i - 1) * sHeight * img.width + (j - 1) * sWidth] * 4
			if (data[pos] > 0) {
				var particle = {
					startX: Math.random() * window.innerWidth,
					startY: Math.random() * window.innerHeight,
					x: imgX + (j - 1) * sWidth, // 不知道为什么img.x为9，他应该返回img图片左上角相对于页面左上角的横坐标
					y: 80 + (i - 1) * sHeight,
					fillStyle:
						'rgba(' +
						data[pos] +
						',' +
						data[pos + 1] +
						',' +
						data[pos + 2] +
						',' +
						data[pos + 3] +
						')',
					delayNum: Math.random() * 200,
					delayCountDownNum: 0,
					currentTimeNum: 0,
					durationNum: 1200
				}
				this.particles.push(particle)
			}
		}
	}
	starsMoveAnimation = new StarsMoveWithMouse(
		particleAnimation.ctx,
		particleAnimation.particles,
		100,
		100
	)
	StarsMoveWithMouse.prototype.starsMoveAnimationFunc = starsMoveAnimation.beginAnimation()
	this.particles[this.particles.length - 1].delayNum = 200
}
ParticleAnimation.prototype.easeInOutExpo = function(t, b, c, d) {
	t /= d / 2
	if (t < 1) return (c / 2) * Math.pow(2, 10 * (t - 1)) + b
	t--
	return (c / 2) * (-Math.pow(2, -10 * t) + 2) + b
}

function Vector(x, y) {
	this.x = x
	this.y = y
}

function StarsMoveWithMouse(context, stars, maxMoveX, maxMoveY) {
	this.ctx = context
	this.maxMoveX = maxMoveX || 500
	this.maxMoveY = maxMoveY || 500
	this.moveStars = []
	this.shootingStarsAnimation = new DrawShootingStars(this.ctx, 0, 0)
	for (var i = 0; i < stars.length; i++) {
		if (Math.random() > 0.8) this.moveStars.push(stars[i])
	}
}

function ShootingStar(ctx, positionX, positionY) {
	this.ctx = ctx
	this.positionX = positionX
	this.positionY = positionY
	this.endColorStop = 1
}

ShootingStar.prototype.draw = function(radius) {
	const ctx = this.ctx
	const positionX = this.positionX
	const positionY = this.positionY
	ctx.save()
	const grid = ctx.createRadialGradient(
		positionX,
		positionY,
		2,
		positionX,
		positionY,
		radius / 2
	)
	grid.addColorStop(0, `rgba(255,255,255,${this.endColorStop})`)
	grid.addColorStop(this.endColorStop, 'rgba(255,255,255,0)')
	grid.addColorStop(1, 'rgba(255,255,255,0)')
	ctx.fillStyle = grid
	ctx.fillRect(positionX - radius / 2, positionY - radius / 2, radius, radius)
	ctx.restore()
	this.endColorStop = this.endColorStop - 0.05
}

function DrawShootingStars(ctx, positionX, positionY) {
	this.starsQueue = []
	this.ctx = ctx
	this.positionX = positionX
	this.positionY = positionY
}

DrawShootingStars.prototype.drawStars = function() {
	if (this.starsQueue.length !== 0) {
		const lastStar = this.starsQueue[this.starsQueue.length - 1]
		this.starsQueue.push(
			new ShootingStar(
				this.ctx,
				(lastStar.positionX + this.positionX) / 2,
				(lastStar.positionY + this.positionY) / 2
			)
		)
	}
	this.starsQueue.push(
		new ShootingStar(this.ctx, this.positionX, this.positionY)
	)
	this.starsQueue.forEach((el) => {
		el.endColorStop < 0 ? this.starsQueue.shift() : el.draw(10)
	})
}

var onMouseMove = function(ev) {
	var positionX = ev.pageX
	var positionY = ev.pageY
	var moveLength = this.calculateMoveLength(
		positionX,
		positionY,
		window.innerWidth,
		window.innerHeight
	)
	this.shootingStarsAnimation.positionX = positionX
	this.shootingStarsAnimation.positionY = positionY
	this.setMoveImg(moveLength, this.shootingStarsAnimation)
}

StarsMoveWithMouse.prototype.beginAnimation = function() {
	var onMouseMoveCb = onMouseMove.bind(this)
	window.addEventListener('mousemove', onMouseMoveCb, false)
	return onMouseMoveCb
}
StarsMoveWithMouse.prototype.endAnimation = function() {
	this.starsMoveAnimationFunc
		? window.removeEventListener('mousemove', this.starsMoveAnimationFunc)
		: null
}
StarsMoveWithMouse.prototype.setMoveImg = function(
	moveLength,
	shootingStarsAnimation
) {
	var curMoveStar = null
	var desX = 0
	var desY = 0
	this.ctx.clearRect(0, 0, window.innerWidth, window.innerHeight)
	shootingStarsAnimation.drawStars()
	this.ctx.save()
	this.ctx.fillStyle = `rgba(255,255,255,${Math.random() * 0.6 + 0.4})`
	for (var i = 0; i < this.moveStars.length; i++) {
		curMoveStar = this.moveStars[i]
		desX = curMoveStar.startX + moveLength.x
		desY = curMoveStar.startY + moveLength.y
		if (desX < 0) desX = desX + window.innerWidth
		else if (desX > window.innerWidth) desX = desX - window.innerWidth
		if (desY < 0) desY = desY + window.innerHeight
		else if (desY > window.innerHeight) desY = desY - window.innerHeight
		this.ctx.fillRect(
			desX,
			desY,
			Math.round(Math.random() * 4),
			Math.round(Math.random() * 4)
		)
	}
	this.ctx.restore()
}
StarsMoveWithMouse.prototype.calculateMoveLength = function(
	positionX,
	positionY,
	LengthX,
	LengthY
) {
	var areaMiddleX = LengthX / 2
	var DegXMeasure = this.maxMoveX / areaMiddleX
	var areaMiddleY = LengthY / 2
	var DegYMeasure = this.maxMoveY / areaMiddleY
	var moveX = (positionX - areaMiddleX) * DegXMeasure
	var moveY = (positionY - areaMiddleY) * DegYMeasure
	return new Vector(moveX, moveY)
}

var particleAnimation = new ParticleAnimation(
	document.getElementById('myParticle')
)
var starsMoveAnimation = null
particleAnimation.beginAnimation()

function ShowLrcWithAudio(audio) {
	this.addToLrcPool.audio = audio
	this.addToLrcPool.objThis = this
}

ShowLrcWithAudio.prototype.beginAnimation = function() {
	for (var i = 0; i < ShowLrcWithAudio.lrcData.length; i++) {
		this.addToLrcPool(ShowLrcWithAudio.lrcData[i])
	}
}

ShowLrcWithAudio.prototype.addToLrcPool = function(SingleLrc) {
	var int = setInterval(function() {
		if (
			SingleLrc.timeStamp - 0.5 <
			ShowLrcWithAudio.prototype.addToLrcPool.audio.currentTime
		) {
			ShowLrcWithAudio.prototype.addToLrcPool.objThis.showWords(SingleLrc)
			clearInterval(int)
		}
	}, 500)
}

ShowLrcWithAudio.prototype.showWords = function(SingleLrc) {
	$('#lrc').text(SingleLrc.lrcContent)
}

var lrcShow = new ShowLrcWithAudio(document.getElementById('song'))

function createMessageBox(msg) {
	var messageBox = $('body')
		.children()
		.eq(1)
	if (messageBox.hasClass('messageBoxActive1') === true) {
		messageBox.text(msg)
		messageBox.toggleClass('messageBoxActive1', false)
		messageBox.toggleClass('messageBoxActive2', true)
	} else {
		messageBox.text(msg)
		messageBox.toggleClass('messageBoxActive2', false)
		messageBox.toggleClass('messageBoxActive1', true)
	}
}

function beginSongAndAnimation() {
	var audioPlayTimes = 0
	document.getElementsByTagName('body')[0].onclick = function() {
		if (audioPlayTimes === 0) {
			$('#words').css('display', 'none')
			audioPlayTimes++
			ShowLrcWithAudio.prototype.addToLrcPool.audio.play()
			starsMoveAnimation.endAnimation()
			$('#heart-bg').css('opacity', '1')
			$('#heartDiv').css('opacity', '1')
			particleAnimation.draw()
		}
	}

	lrcShow.beginAnimation()
}

function printWords() {
	var words = configData.words

	var wordIndex = 0
	createMessageBox(words[wordIndex])
	wordIndex++
	var wordsInter = setInterval(function() {
		if (words[wordIndex]) {
			createMessageBox(words[wordIndex])
			wordIndex++
			if (!words[wordIndex]) beginSongAndAnimation()
		} else {
			$('#words').css('opacity', '1')
			clearInterval(wordsInter)
		}
	}, 10000)
}
